package com.bestom.bestoma10demo;

import android.annotation.SuppressLint;
import android.os.Handler;
import android.os.Message;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.InetAddress;
import java.net.URL;

import javax.net.ssl.HttpsURLConnection;

public class NetWorkUtils {

    /**
     * Check if the Internet address is accessible - use ping
     *
     * @param address  The domain name or IP address to check
     * @param callback Check the result callback (whether it can ping the address) {@see java.lang.Comparable<T>}
     */
    public static void isNetWorkAvailable(final String address, final Comparable<Boolean> callback) {
        @SuppressLint("HandlerLeak")
        final Handler handler = new Handler() {
            @Override
            public void handleMessage(Message msg) {
                super.handleMessage(msg);
                if (callback != null) {
                    callback.compareTo(msg.arg1 == 0);
                }
            }

        };
        new Thread(() -> {
            Runtime runtime = Runtime.getRuntime();
            Message msg = new Message();
            try {
                Process pingProcess = runtime.exec("/system/bin/ping -c 1 " + address);
                InputStreamReader isr = new InputStreamReader(pingProcess.getInputStream());
                BufferedReader buf = new BufferedReader(isr);
                if (buf.readLine() == null) {
                    msg.arg1 = -1;
                } else {
                    msg.arg1 = 0;
                }
                buf.close();
                isr.close();
            } catch (Exception e) {
                msg.arg1 = -1;
                e.printStackTrace();
            } finally {
                runtime.gc();
                handler.sendMessage(msg);
            }
        }).start();
    }

    /**
     * Check if the Internet address is accessible - use GET requests
     *
     * @param urlStr   The URL to check
     * @param callback Check the result callback (whether the GET request succeeds) {@see java.lang.Comparable<T>}
     */
    public static void isNetWorkAvailableOfGet(final String urlStr, final Comparable<Boolean> callback) {
        @SuppressLint("HandlerLeak")
        final Handler handler = new Handler() {
            @Override
            public void handleMessage(Message msg) {
                super.handleMessage(msg);
                if (callback != null) {
                    callback.compareTo(msg.arg1 == 0);
                }
            }

        };
        new Thread(() -> {
            Message msg = new Message();
            try {
                Connection conn = new Connection(urlStr);
                Thread thread = new Thread(conn);
                thread.start();
                thread.join(3 * 1000);
                int resCode = conn.get();
                msg.arg1 = resCode == 200 ? 0 : -1;
            } catch (Exception e) {
                msg.arg1 = -1;
                e.printStackTrace();
            } finally {
                handler.sendMessage(msg);
            }
        }).start();
    }

    /**
     * The HttpURLConnection request thread
     */
    private static class Connection implements Runnable {
        private String urlStr;
        private int responseCode;

        public Connection(String urlStr) {
            this.urlStr = urlStr;
        }

        public void run() {
            try {
                URL url = new URL(urlStr);
                HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
                conn.setRequestMethod("GET");
                conn.connect();
                set(conn.getResponseCode());
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        public synchronized void set(int responseCode) {
            this.responseCode = responseCode;
        }

        public synchronized int get() {
            return responseCode;
        }
    }

    /**
     * Check if the Internet address is accessible - use DNS resolution
     *
     * @param hostname   The domain name or IP to check
     * @param callback Check the result callback (whether it can be resolved successfully) {@see java.lang.Comparable<T>}
     */
    public static void isNetWorkAvailableOfDNS(final String hostname, final Comparable<Boolean> callback) {
        @SuppressLint("HandlerLeak")
        final Handler handler = new Handler() {
            @Override
            public void handleMessage(Message msg) {
                super.handleMessage(msg);
                if (callback != null) {
                    callback.compareTo(msg.arg1 == 0);
                }
            }

        };
        new Thread(() -> {
            Message msg = new Message();
            try {
                DNSParse parse = new DNSParse(hostname);
                Thread thread = new Thread(parse);
                thread.start();
                thread.join(3 * 1000);
                InetAddress resCode = parse.get();
                msg.arg1 = resCode == null ? -1 : 0;
            } catch (Exception e) {
                msg.arg1 = -1;
                e.printStackTrace();
            } finally {
                handler.sendMessage(msg);
            }
        }).start();
    }

    /**
     * DNS resolves the thread
     */
    private static class DNSParse implements Runnable {
        private String hostname;
        private InetAddress address;

        public DNSParse(String hostname) {
            this.hostname = hostname;
        }

        public void run() {
            try {
                set(InetAddress.getByName(hostname));
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        public synchronized void set(InetAddress address) {
            this.address = address;
        }

        public synchronized InetAddress get() {
            return address;
        }
    }
}
